package com.michaelbulava.TFS.vcs.ui.configuration;

import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.ComponentWithBrowseButton;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.ui.SortedComboBoxModel;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.configuration.ProjectPreferences;
import com.michaelbulava.TFS.log.FileLogger;
import com.microsoft.tfs.util.Check;
import com.microsoft.vss.client.core.utils.StringUtil;
import org.apache.log4j.Level;

import javax.swing.*;
import javax.swing.event.ListDataListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Comparator;
import java.util.ResourceBundle;

/**
 * Created by MichaelA on 9/3/2015.
 * I'm ripping off most of the design and settings from eclipse's settings for TFS...
 */
public class TFSProjectConfigurableForm extends JPanel{
    private JCheckBox automaticallyConnectTeamExplorerCheckBox;
    private JCheckBox connectMappedProjectsToCheckBox;
    private JCheckBox acceptUntrustedSSLCertificatesCheckBox;
    private JButton supportInformationButton;
    private JTabbedPane tabbedPane1;

    //Debugging tab variables
    private JCheckBox enableDebugLogCheckBox;
    private JLabel debuglogLocationLabel;
    private ComboBox mimDebugLogLevelComboBox;
    private TextFieldWithBrowseButton debugLogLocation;


    private final Project myProject;


    public TFSProjectConfigurableForm(Project project){
        super();
        Check.notNull(project, "project");
        this.myProject = project;

        setLayout(new GridLayoutManager(6, 1, new Insets(4, 4, 4, 4), -1, -1));
        final JLabel label1 = new JLabel();
        label1.setText(Messages.getString("TFSProjectConfigurableForm.GeneralSettingsLabel"));
        add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        //Hiding and disabling automaticallyConnectTeamExplorerCheckBox because there is no Team Explorer window in the plugin yet.
        automaticallyConnectTeamExplorerCheckBox = new JCheckBox();
        automaticallyConnectTeamExplorerCheckBox.setEnabled(false);
        automaticallyConnectTeamExplorerCheckBox.setVisible(false);
        automaticallyConnectTeamExplorerCheckBox.setText(Messages.getString("TFSProjectConfigurableForm.AutomaticallyConnectExplorer"));
        add(automaticallyConnectTeamExplorerCheckBox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        connectMappedProjectsToCheckBox = new JCheckBox();
        connectMappedProjectsToCheckBox.setText(Messages.getString("TFSProjectConfigurableForm.ConnectMappedProjects"));
        add(connectMappedProjectsToCheckBox, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        acceptUntrustedSSLCertificatesCheckBox = new JCheckBox();
        acceptUntrustedSSLCertificatesCheckBox.setText(Messages.getString("TFSProjectConfigurableForm.AcceptUntrustedCertificates"));
        add(acceptUntrustedSSLCertificatesCheckBox, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        supportInformationButton = new JButton();
        supportInformationButton.setText(Messages.getString("TFSProjectConfigurableForm.SuportInfoButton"));
        add(supportInformationButton, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        //TablePane is here for expansion for other options that may be needed later, since we don't need now make it invisable
        tabbedPane1 = new JBTabbedPane();
        tabbedPane1.setVisible(true);
        add(tabbedPane1, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null,
                new Dimension(200, 200), null, 0, false));

        //Debugging panel
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(5, 1, new Insets(0, 0, 0, 0), -1, -1));
        tabbedPane1.addTab(Messages.getString("TFSProjectConfigurableForm.Debugging.Title"), panel2);

        enableDebugLogCheckBox = new JCheckBox();
        enableDebugLogCheckBox.setText(Messages.getString("TFSProjectConfigurableForm.Debugging.EnbableLabel"));
        panel2.add(enableDebugLogCheckBox, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));

        final Spacer spacer1 = new Spacer();
        panel2.add(spacer1, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL,
                1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));

        debugLogLocation = new TextFieldWithBrowseButton();
        panel2.add(debugLogLocation, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_HORIZONTAL,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));

        debuglogLocationLabel = new JLabel();
        debuglogLocationLabel.setText(Messages.getString("TFSProjectConfigurableForm.Debugging.SelectLocationLabel"));
        panel2.add(debuglogLocationLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
                null, null, 0, false));
        debugLogLocation.setEnabled(false);
        debuglogLocationLabel.setEnabled(false);

        final JPanel panel3 = new JPanel();
        panel3.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel2.add(panel3, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0,
                false));

        final JLabel label2 = new JLabel();
        label2.setText(Messages.getString("TFSProjectConfigurableForm.Debugging.MinimumDebugLogLevelLabel"));
        panel3.add(label2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        label2.setEnabled(false);

        mimDebugLogLevelComboBox = new ComboBox();
        mimDebugLogLevelComboBox.setEnabled(false);
        panel3.add(mimDebugLogLevelComboBox, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED,
                null, null, null, 0, false));

        debuglogLocationLabel.setLabelFor(debugLogLocation);
        FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
        ComponentWithBrowseButton.BrowseFolderActionListener listener =  new ComponentWithBrowseButton
                .BrowseFolderActionListener(Messages.getString("TFSProjectConfigurableForm.Debugging.BrowseDialogTitle"),
                Messages.getString("TFSProjectConfigurableForm.Debugging.Description"),
                debugLogLocation, myProject, descriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
        debugLogLocation.addActionListener(listener);

        mimDebugLogLevelComboBox.setModel(new DebugLevelModel());
        mimDebugLogLevelComboBox.setRenderer(new DebugLevelRender());

//        enableDebugLogCheckBox.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                AbstractButton abstractButton = (AbstractButton) e.getSource();
//                boolean selected = abstractButton.getModel().isSelected();
//
//                debugLogLocation.setEnabled(selected);
//                debuglogLocationLabel.setEnabled(selected);
//                mimDebugLogLevelComboBox.setEnabled(selected);
//                label2.setEnabled(selected);
//            }
//        });
        enableDebugLogCheckBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                AbstractButton abstractButton = (AbstractButton) e.getSource();
                boolean selected = abstractButton.getModel().isSelected();

                debugLogLocation.setEnabled(selected);
                debuglogLocationLabel.setEnabled(selected);
                mimDebugLogLevelComboBox.setEnabled(selected);
                label2.setEnabled(selected);
            }
        });
    }

    //ripped out this from UnnamedConfiguable just so the TFSProjectConfigurable can directly call the for
    /**
     * Indicates whether the Swing form was modified or not.
     * This method is called very often, so it should not take a long time.
     *
     * @return {@code true} if the settings were modified, {@code false} otherwise
     */
    public final boolean isModified(){
        ProjectPreferences prefs = ProjectPreferences.getProjectInstance(myProject);
        if (prefs.getConnectTeamExplorer() != automaticallyConnectTeamExplorerCheckBox.isSelected())
            return true;
        if (prefs.getReconnectModules() != connectMappedProjectsToCheckBox.isSelected())
            return true;
        if (prefs.getAcceptUntrustedCerts() != acceptUntrustedSSLCertificatesCheckBox.isSelected())
            return true;
        if(FileLogger.getLogToFile() != enableDebugLogCheckBox.isSelected())
            return true;
        if (FileLogger.getMinimumLoggingLevel() != (Level)mimDebugLogLevelComboBox.getSelectedItem())
            return true;
        if (!FileLogger.getLoggingLocation().equals(debugLogLocation.getText()))
            return true;
        return false;
    }

    /**
     * Stores the settings from the Swing form to the configurable component.
     * This method is called on EDT upon user's request.
     *
     * @throws ConfigurationException if values cannot be applied
     */
    public final void apply() throws ConfigurationException{
        ProjectPreferences prefs = ProjectPreferences.getProjectInstance(myProject);
        prefs.setConnectTeamExplorer(automaticallyConnectTeamExplorerCheckBox.isSelected());
        prefs.setReconnectModule(connectMappedProjectsToCheckBox.isSelected());
        prefs.setAcceptUntrustedCerts(acceptUntrustedSSLCertificatesCheckBox.isSelected());

        FileLogger.setMinimumLoggingLevel((Level)mimDebugLogLevelComboBox.getSelectedItem());
        FileLogger.setLoggingLocation(debugLogLocation.getText());
        FileLogger.setLogToFile(enableDebugLogCheckBox.isSelected());
    }

    /**
     * Loads the settings from the configurable component to the Swing form.
     * This method is called on EDT immediately after the form creation or later upon user's request.
     */
    public final void reset(){
        ProjectPreferences prefs = ProjectPreferences.getProjectInstance(myProject);
        automaticallyConnectTeamExplorerCheckBox.setSelected(prefs.getConnectTeamExplorer());
        connectMappedProjectsToCheckBox.setSelected(prefs.getReconnectModules());
        acceptUntrustedSSLCertificatesCheckBox.setSelected(prefs.getAcceptUntrustedCerts());

        enableDebugLogCheckBox.setSelected(FileLogger.getLogToFile());

        if (!StringUtil.isNullOrEmpty(FileLogger.getLoggingLocation()))
            debugLogLocation.setText(FileLogger.getLoggingLocation());
        else
            debugLogLocation.setText(System.getProperty("user.home"));

        mimDebugLogLevelComboBox.setSelectedItem(FileLogger.getMinimumLoggingLevel());

    }

    private static class DebugLevelModel extends SortedComboBoxModel<Level> {

        private static Comparator<Level> levelComparator = new Comparator<Level>() {
            @Override
            public int compare(Level o1, Level o2) {
                return o1.toInt() - o2.toInt();
            }
        };

        public DebugLevelModel() {
            super(levelComparator);

            super.addAll(new Level[] {
                    Level.TRACE,
                    Level.DEBUG,
                    Level.INFO,
                    Level.WARN,
                    Level.ERROR,
                    Level.FATAL,
            });
        }
    }

    private static class DebugLevelRender extends DefaultListCellRenderer{

        @Override
        public Component getListCellRendererComponent(
                JList<?> list,
                Object value,
                int index,
                boolean isSelected,
                boolean cellHasFocus){
            if (value instanceof Level){
                Level lvl = (Level)value;
                value = lvl.toString();
            }
            return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        }
    }
}
